/**
 * @file        interface.cpp
 * @brief       gtdshell command line interface handling.
 *
 * @author      Emre Turkay <emreturkay at gmail>
 * @date        May.31.2008
 *
 * Copyright Emre Turkay 2009
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file COPYRIGHT or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 */

#include "interface.hpp"
#include "rl.hpp"

#include <boost/bind.hpp>
#include <boost/tokenizer.hpp>

#include <algorithm>
#include <cstdlib>

/*
 * class action_info implementation.
 */

action_info::action_info(function_type f, const std::string& desc)
    : function_(f),
      description_(desc)
{
}

std::vector<std::string>
action_info::complete(const std::vector<std::string>& args, bool complete)
{
    if (!completer_.empty())
        return completer_(args, complete);
    return std::vector<std::string>();
}

void action_info::operator()(const args_type& args)
{
    function_(args);
}

/*
 * class interface implementation.
 */

interface::interface()
    : reader_(rl::reader::instance())
{
    reader_.completer(boost::bind(&interface::completer, this, _1, _2));
}

void interface::command(const std::string& text,
                        function_type action,
                        const std::string& description)
{
    actions_[text] = action_info(action, description);
}

void interface::set_completer(const std::string& text, completer_type completer)
{
    actions_type::iterator i = actions_.find(text);
    if (i != actions_.end())
        i->second.completer(completer);
}

bool interface::process()
{
    bool eof;

   std::string line = reader_.read(eof, "> ");

    if (eof)
    {
        std::cout << "bye" << std::endl;
        return false;
    }

    std::vector<std::string> result;

    typedef boost::escaped_list_separator<char> tokenizer_func;
    boost::tokenizer<tokenizer_func>
        tok(line, tokenizer_func("\\", " \t", "\""));
    std::copy(tok.begin(), tok.end(), std::back_inserter(result));

    if (result.size())
    {
        actions_type::iterator map_iter = actions_.find(result[0]);
        if (map_iter == actions_.end())
            std::cout << "Unknown command: " << result[0] << std::endl;
        else
        {
            result.erase(result.begin());
            map_iter->second(result);
        }
    }

    return true;
}

void interface::help()
{
    for(actions_type::const_iterator i = actions_.begin();
            i != actions_.end(); ++i)
    {
        std::cout << i->first << '\t' << i->second.description() << std::endl;
    }
}

void interface::write(const std::string& value) const
{
    std::cout << value << std::endl;
}

std::vector<std::string>
interface::completer(const std::vector<std::string>& args, bool complete)
{
    std::vector<std::string> result;

    bool match_all = (args.size() == 0);
    bool match_cmd = (args.size() == 1) && !complete;

    if (match_all || match_cmd)
    {
        std::vector<std::string> commands;
        for (actions_type::const_iterator i = actions_.begin();
             i != actions_.end(); ++i)
        {
            commands.push_back(i->first);
        }

        if (match_all)
            return commands;
        
        if (match_cmd)
            return rl::fetch_matches(args[0], commands);
    }

    if (args.size() > 1)
    {
        actions_type::iterator i = actions_.find(args[0]);
        if (i != actions_.end())
            return i->second.complete(args, complete);
    }

    return result;
}
